-- Copyright (c) 2024 Huawei Technologies Co., Ltd.
-- openUBMC is licensed under Mulan PSL v2.
-- You can use this software according to the terms and conditions of the Mulan PSL v2.
-- You may obtain a copy of Mulan PSL v2 at:
--         http://license.coscl.org.cn/MulanPSL2
-- THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
-- EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
-- MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
-- See the Mulan PSL v2 for more details.

-- Description: 上电锁
local class = require "mc.class"
local fructl_handler = require 'infrastructure.fructl'
local skynet = require 'skynet'
local log = require 'mc.logging'

local DEFAULT_LOCK_TIME<const> = 1000 --5min
local LOCK_FOREVER<const> = 0xFFFF --永久锁

local power_lock = class()

---@param is_prolong 是否需要延长锁时间
---@param lock_time 加锁时间
---@param unlock_flag 锁释放标记
function power_lock:ctor(system_id)
    self.is_prolong = false
    self.lock_time = DEFAULT_LOCK_TIME
    self.unlock_flag = false
    self.reason = 'bios'
    self.app_name = 'Upgrade'
    self.system_id = system_id
end

local function get_lock_time(time)
    if not time then
        return DEFAULT_LOCK_TIME
    end
    return time
end

function power_lock:lock_internal(lock_time, is_lock)
    return fructl_handler.set_power_on_lock(is_lock, lock_time, self.reason, self.app_name, self.system_id)
end

function power_lock:set_reason(reason)
    self.reason = reason
end

function power_lock:set_lock_time(lock_time)
    self.lock_time = lock_time
end

function power_lock:finish_judge()
    return self.unlock_flag or self.forevery_lock_flag
end

-- 延长锁任务
function power_lock:prolong_lock_task()
    -- 2分钟延长一次
    local prolong_period = 2 * 60 * 100

    -- 一次性任务。失败之后重试，间隔10s
    skynet.fork_once(function()
        while true do
            if self:finish_judge() then
                log:error('[bios]power_lock: system %s prolong lock task no need start.', self.system_id)
                break
            end
            skynet.sleep(prolong_period)
            if self:finish_judge() then
                log:error('[bios]power_lock: system %s prolong lock task finish, unlock fructrl.', self.system_id)
                break
            end
            self:lock_internal(self.lock_time, true)
            if self.unlock_flag then
                log:error('[bios]power_lock: system %s prolong lock task stop, unlock fructrl.', self.system_id)
                self:unlock()
                break
            elseif self.forever_lock_flag then
                log:error('[bios]power_lock: system %s prolong lock task stop, lock forever.', self.system_id)
                self:lock_forever()
                break
            end
        end
    end)
end

-- 延长锁时间
function power_lock:prolong_lock_time()
    self:lock_internal(self.lock_time, true)
end

-- 普通加锁:不指定加锁时间,则设置为默认的加锁时间（5min）
function power_lock:lock(time)
    local lock_time = get_lock_time(time)
    local res = self:lock_internal(lock_time, true)
    if not res then
        log:error('[bios]power_lock: system %s lock fail.', self.system_id)
        return false
    end
    self.lock_time = lock_time
    log:notice('[bios]power_lock: system %s lock success.', self.system_id)
    return true
end

-- 加锁直到成功,支持延长锁时间
function power_lock:lock_until_success(time, is_prolong, reason)
    local lock_time = get_lock_time(time)
    self.reason = reason
    self.app_name = 'bios'
    log:error('[bios]lock_until_success: system %s lock start.', self.system_id)
    while true do
        local res = self:lock_internal(lock_time, true)
        if res then
            break
        end
        skynet.sleep(50)
    end
    self.lock_time = lock_time
    self.is_prolong = is_prolong
    if is_prolong then
        self:prolong_lock_task()
    end
end

-- 永久锁
function power_lock:lock_forever()
    local res = self:lock_internal(LOCK_FOREVER, true)
    self.forever_lock_flag = true
    if not res then
        log:error('[bios]power_lock: system %s unlock fail.', self.system_id)
        return false
    end
    self.lock_time = LOCK_FOREVER
    return true
end

-- 释放锁
function power_lock:unlock()
    local res = self:lock_internal(self.lock_time, false)
    self.unlock_flag = true
    if not res then
        log:error('[bios]power_lock: system %s unlock fail.', self.system_id)
        return false
    end
    return true
end

return power_lock